﻿using EarthGrid.core;
using OSGeo.OGR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;


namespace EarthGrid.shp
{
    public class GridShpTool
    {
        #region 中文乱码处理
        [DllImport("gdal204.dll", EntryPoint = "OGR_F_GetFieldAsString", CallingConvention = CallingConvention.Cdecl)]
        public extern static System.IntPtr OGR_F_GetFieldAsString(HandleRef handle, int i);

        /// <summary>
        /// 读取时调用
        /// </summary>
        /// <param name="fe">当前要素</param>
        /// <param name="index">索引</param>
        /// <returns></returns>
        public static String GetFieldValueString(Feature fe, int index)
        {
            IntPtr pNativeData = OGR_F_GetFieldAsString(OSGeo.OGR.Feature.getCPtr(fe), index);
            if (pNativeData == IntPtr.Zero)
                return null;
            string s = Marshal.PtrToStringAnsi(pNativeData);
            return s;
        }

        [DllImport("gdal204.dll", EntryPoint = "OGR_F_SetFieldString", CallingConvention = CallingConvention.Cdecl)]
        public extern static void OGR_F_SetFieldString(HandleRef handle, int index, string val);
        /// 写入时调用
        /// <param name="fe"></param>
        /// <param name="index">索引</param>
        /// <param name="val">值</param>
        public static void SetFieldValueString(Feature fe, int index, string val)
        {

            //说白了封装C#版本的时候做了一层UTF8的转换
            OGR_F_SetFieldString(OSGeo.OGR.Feature.getCPtr(fe), index, val);
        }
        #endregion

        string wkt = "GEOGCS[\"China Geodetic Coordinate System 2000\",DATUM[\"China_2000\",SPHEROID[\"CGCS2000\",6378137,298.257222101,AUTHORITY[\"EPSG\",\"1024\"]],AUTHORITY[\"EPSG\",\"1043\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4490\"]]";//投影坐标系的WKT
        public string FilePath { get => FilePath; set => FilePath = value; }

        DataSource ds;
        Layer layer;
        FeatureDefn featureDefn;

        public static void InitGDAL()
        {
            GdalConfiguration.ConfigureGdal();
        }
        /// <summary>
        /// 创建CGCS2000大地坐标系的shp文件
        /// EPSG:4490
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="geometryType">空间数据类型</param>
        /// <returns></returns>
        public GridShpTool (String filePath, wkbGeometryType geometryType)
        {
            InitGDAL();

            string strDriver = "ESRI Shapefile";
            Driver oDriver = Ogr.GetDriverByName(strDriver);

            ds = oDriver.CreateDataSource(filePath, null);

            OSGeo.OSR.SpatialReference sr = new OSGeo.OSR.SpatialReference(wkt);
            layer = ds.CreateLayer(geometryType.ToString(), sr, geometryType, null);
            featureDefn = CreateFeatureDefn();
        }

        public FeatureDefn CreateFeatureDefn()
        {
            FieldDefn fieldDefn = new FieldDefn("level", FieldType.OFTInteger);
            layer.CreateField(fieldDefn, 1);
            layer.CreateField(new FieldDefn("code", FieldType.OFTString), 1);
            layer.CreateField(new FieldDefn("minx", FieldType.OFTReal), 1);
            layer.CreateField(new FieldDefn("miny", FieldType.OFTReal), 1);
            layer.CreateField(new FieldDefn("maxx", FieldType.OFTReal), 1);
            layer.CreateField(new FieldDefn("maxy", FieldType.OFTReal), 1);
            FeatureDefn featureDefn = layer.GetLayerDefn();
            return featureDefn;
        }

        public Feature CreateFeature(Grid grid)
        {
            Feature f = new Feature(featureDefn);
            f.SetField("level", grid.Level);
            f.SetField("code", grid.GetGridCode());

            Geometry geometry = new Geometry(wkbGeometryType.wkbPolygon);
            double minx = To十进制(grid.MinLon);
            double miny = To十进制(grid.MinLat);
            double maxx = To十进制(grid.MaxLon);
            double maxy = To十进制(grid.MaxLat);

            f.SetField("minx", minx);
            f.SetField("miny", miny);
            f.SetField("maxx", maxx);
            f.SetField("maxy", maxy);
            Geometry ring = new Geometry(wkbGeometryType.wkbLinearRing);
            ring.AddPoint_2D(minx, miny);
            ring.AddPoint_2D(maxx, miny);
            ring.AddPoint_2D(maxx, maxy);
            ring.AddPoint_2D(minx, maxy);
            ring.AddPoint_2D(minx, miny);
           // ring.AddPoint(minx, miny, 0d);
            geometry.AddGeometry(ring);
            
            f.SetGeometry(geometry);

            return f;
        }

        public void ExportFeatures(List<Feature> features/*, MainModel mainModel*/)
        {

            layer.StartTransaction();
            for (int i = 0; i < features.Count; i++)
            {
                Feature f = features[i];
                try
                {
                    layer.CreateFeature(f);
                    //mainModel.Count++;
                }
                catch (Exception e)
                {
                    //Log.InfoAsync(e.Message);
                }
                finally
                {
                    f.Dispose();
                }
                if (i % 1000 == 0)
                {
                    layer.CommitTransaction();
                    layer.StartTransaction();
                    layer.SyncToDisk();
                }
            }
            layer.CommitTransaction();
            layer.SyncToDisk();
        }

        private double To十进制(LonLat p)
        {
            double d = p.Du;
            if (p.Type == LonLatEnum.lon)
            {
                d = d > 180 ? 180 : d;
                d = d < -180 ? -180 : d;
            }
            else
            {
                d = d > 90 ? 90 : d;
                d = d < -90 ? -90 : d;
            }
            double f = p.Fen > 60 ? 60 : p.Fen;
            f = f < -60 ? -60 : f;
            double m = p.Miao > 60 ? 60 : p.Miao;
            m = m < -60 ? -60 : m;

            d += (double)f / 60;
            d += m / 3600;
            return d;
        }
    }
}
